import unittest
from functionBinding import functionBinding
from functionDef import functionDef
from application import application
from Return import Return
from builtin import *
from varRef import varRef
from jsobject import *
from interpreter import interpreter
from endvals import *
from objectOps import *
from sequence import *
from conditionals import *
from sequence import *
from varBinding import *
from varMut import *
from customExceptions import *


class TestFunctions(unittest.TestCase):
	def testBasicFunction(self):
		p = functionBinding( [
														functionDef("h",[], 
															Return(stringval("test!"))
														 )
													], 
													Return(application("h", [] ) ) 
												)
		i = interpreter(p)
		assert i.execute().__str__() == "test!", "testBasicFunction expected to return \"test!\""

#--	------------------------------------------------------------------
	
	def testBasicFunctionTooFewArgs(self):
		p = functionBinding( [
														functionDef("h",["a"], 
															Return(stringval("test!"))
														 )
													], 
													Return(application("h", [] ) ) 
												)
		i = interpreter(p)
		try:
			i.execute()
		except GeneralException:
			assert True
		else:
			assert False, "testBasicFunction expected to return None and print error"	

#--	------------------------------------------------------------------
		
	def testBasicFunctionTooManyArgs(self):
		p = functionBinding( [
														functionDef("h",[], 
															Return(stringval("test!"))
														 )
													], 
													Return(application("h", ["a"] ) ) 
												)
		i = interpreter(p)
		try:
			i.execute()
		except GeneralException:
			assert True
		else:
			assert False, "testBasicFunctionTooManyArgs expected to return None and print error"	
		

#--	------------------------------------------------------------------
		
	def testFunctionArgs(self):
		p = functionBinding([functionDef("a",["x","y","z"], 
																		Return(application("+", [varRef("x"), application("*",[varRef("y"),varRef("z")] ) ] ))
																		   )
											   ],
											   Return(application("a",[integer(1),integer(2), integer(2)])))
		i = interpreter(p)
		assert i.execute() == 5, "testFunctionArgs Failed - First case a(1,2,2)"
		p = functionBinding([functionDef("a",["x","y","z"], 
																		Return( application("+", [varRef("x"),  application("*",[varRef("y"),varRef("z")] ) ] ))
																		  )
											   ],
											   Return(application("a",[integer(3),integer(5), integer(5)])))
		i = interpreter(p)
		assert i.execute() == 28, "testFunctionArgs Failed - First case a(1,2,2)"
		p = functionBinding([functionDef("a",["x","y","z"], 
																		Return(application("+", [varRef("x"), application("*",[varRef("y"),varRef("z")] ) ] ))
																		   )
											   ],
											   Return(application("a",[integer(5),integer(6), integer(1)])))
		i = interpreter(p)
		assert i.execute() == 11, "testFunctionArgs Failed - First case a(1,2,2)"		

#--	------------------------------------------------------------------

	def testRecursiveFunctions(self):
		p = functionBinding( 
		[functionDef("b",["x"], 
			sequence(
				[
					application("print",[varRef("x")]),
						ifthen(application(">",[varRef("x"),integer(0)]),
				#if
						 Return(application("b",[application("-",[varRef("x"),integer(1)])] ) ), 
				#then
						 Return(integer(0)) 
						)
				]
			))
		], Return(application("b", [integer(10)] ) ) )
		i = interpreter(p)
		assert i.execute() == 0, "testMutualFunctions Failed! Should Return 0, See above printout for clues!"

#--	------------------------------------------------------------------
		
	def testMutualFunctions(self):
		p = functionBinding( 
		[functionDef("a",["x"], 
			sequence(
				[
					application("print",[varRef("x")] ),
					Return(application("b",[application("-", [varRef("x"),integer(1)] )] ) )
				]
			)), 
		functionDef("b",["x"], 
			sequence(
				[
					application("print",[varRef("x")]),
						ifthen(application(">",[varRef("x"),integer(0)]),
				#if
						 Return(application("a",[application("-",[varRef("x"),integer(1)])] ) ), 
				#then
						 Return(integer(0)) 
						)
				]
			))
		], Return(application("a", [integer(10)] ) ) )
		i = interpreter(p)
		assert i.execute() == 0, "testMutualFunctions Failed! Should Return 0, See above printout for clues!"
		
if __name__ == '__main__':
    unittest.main()
